/**
 * @author Horváth Miklós 
 */
import greenfoot.*;

public class GenAlg  
 {
  private static final int POPULACIO_MERET = 30;
  private static final int GENEK_SZAMA = 50;
  private static final int ELIT_RATA = 4;
  private static final int MUTACIOS_RATA = 5;
  private static final int MUTANS_GENEK = 5;  
  private static final int UTODSZAM = 2;
  private static final int ELIT_UTODSZAM = 4;
  
  private int[][][] populacio = new int[POPULACIO_MERET][][];
  
  private int egyed_id = 0;
  private int generacio_szamlalo = 0;
  
  public GenAlg()
   {
    populaciot_general();
   }
 
  private int[][] egyedet_general()
   {
    int[][] egyed = new int[4][];
    egyed[0] = new int[GENEK_SZAMA]; // X koordináta génjei
    egyed[1] = new int[GENEK_SZAMA]; // Y koordináta génjei
    egyed[2] = new int[1]; // Jellemet meghatározó gén    
    egyed[3] = new int[1]; // Fitness érték
    egyed[2][0] = Greenfoot.getRandomNumber(4);
    for (int i=0; i<GENEK_SZAMA; i++)
     {
      while (true)
       {
        egyed[0][i] = Greenfoot.getRandomNumber(3) - 1;
        egyed[1][i] = Greenfoot.getRandomNumber(3) - 1;
        if (egyed[0][i] != 0 || egyed[1][i] != 0) break;
       }
     }
    return egyed;
   }
   
  private void populaciot_general()
   {
    for (int i=0; i<POPULACIO_MERET; i++)
     {
      populacio[i] = egyedet_general();
     }
   }

  public int[] x_genek_leker()
   {
    return populacio[egyed_id][0];
   }
 
  public int[] y_genek_leker()
   {
    return populacio[egyed_id][1];
   } 
   
  public int jellem_leker()
   {
    return populacio[egyed_id][2][0];
   }
   
  public int id_leker()
   {
    return egyed_id;
   }
   
  public int generacioszam_leker()
   {
    return generacio_szamlalo;
   }
   
  private void pop_fitness()
   {
    System.out.println("Fitness értékek: ");
    for (int i=0; i<POPULACIO_MERET; i++)
     {
      System.out.println(i+". egyed: "+populacio[i][3][0]);
     }
   }
   
  private void rendez()
   {
    int[][] atmeneti;
    pop_fitness();
    int veg=POPULACIO_MERET-1;
    while(veg > 0)
     {
      for (int i=0; i<veg; i++)
       {
        if (populacio[i][3][0] < populacio[i+1][3][0])
         {
          atmeneti = populacio[i];
          populacio[i] = populacio[i+1];
          populacio[i+1] = atmeneti;
         }
       }
      veg--;
     }
    System.out.println("Rendezve!");
    pop_fitness();
   }
   
  private int[][][] keresztezes()
   {
    int[][][] uj_populacio = new int[POPULACIO_MERET][][];
    int anya = 0;
    int gyerek = 0;
    System.out.println("KERESZTEZÉSBE BELÉPVE!!!");
    for(int i=0; i<POPULACIO_MERET; i++)
     {
      int[][] egyed = new int[4][];
      egyed[0] = new int[GENEK_SZAMA]; // X koordináta génjei
      egyed[1] = new int[GENEK_SZAMA]; // Y koordináta génjei
      egyed[2] = new int[1]; // Jellemet meghatározó gén    
      egyed[3] = new int[1]; // Fitness érték      
      int apa = Greenfoot.getRandomNumber(POPULACIO_MERET);
      if (Greenfoot.getRandomNumber(2) == 1)
       {
        egyed[2][0] = populacio[anya][2][0];
       }
      else
       {
        egyed[2][0] = populacio[apa][2][0];       
       }
      System.out.println("ANYA: "+anya+" APA: "+apa);
      for(int j=0; j<GENEK_SZAMA; j++)
       {
        if (Greenfoot.getRandomNumber(2) == 1)
         {
          egyed[0][j] = populacio[anya][0][j];
          egyed[1][j] = populacio[anya][1][j];
         }
        else
         {
          egyed[0][j] = populacio[apa][0][j];
          egyed[1][j] = populacio[apa][1][j];
         }
       }
      gyerek++;
      if (anya < ELIT_RATA && gyerek > ELIT_UTODSZAM)
       {
        anya++;
        gyerek = 0;        
       }
      else if (anya >= ELIT_RATA && gyerek > UTODSZAM)
       {
        anya++;
        gyerek = 0;
       }
      uj_populacio[i] = egyed;
     }
    System.out.println("KERESZTEZÉS VÉGÉN!!!");
    return uj_populacio;
   }
  
  private void mutacio()
   {
    for (int i = MUTACIOS_RATA; i>0; i--)
     {
      int mutans = Greenfoot.getRandomNumber(POPULACIO_MERET);
      populacio[mutans][2][0] = Greenfoot.getRandomNumber(4);
      for (int j = MUTANS_GENEK; j>0; j--)
       {
        int mutans_gen = Greenfoot.getRandomNumber(GENEK_SZAMA);
        while (true)
         {
          populacio[mutans][0][mutans_gen] = Greenfoot.getRandomNumber(3) - 1;
          populacio[mutans][1][mutans_gen] = Greenfoot.getRandomNumber(3) - 1;
          if (populacio[mutans][0][mutans_gen] != 0 || populacio[mutans][1][mutans_gen] != 0) break;
         }
       }
     }
    System.out.println("--------------------MUTÁCIÓ VÉGE---------------------");
   }
   
  private void ujgeneracio()
   {
    System.out.println("--------------------ÚJ GENERÁCIÓ---------------------");
    rendez();
    populacio = keresztezes();
    System.out.println("--------------------KERESZTEZVE---------------------");
    mutacio();
    generacio_szamlalo++;
   }
   
  public void fitness_atadas(int fitness)
   {
    populacio[egyed_id][3][0] = fitness;
    egyed_id++;
    if (egyed_id == POPULACIO_MERET)
     {
      ujgeneracio();
      egyed_id = 0;
     }
   }
 }
